# -*- coding: utf-8 -*-

import os
import sys
sys.path.append('./common')
from processing import list2dict, SpliceData
from metric import *
from recommend import *
import threading
import time

def my_test(data, recommend_func = RandomCF, N = 20, M = 8, desc = True, *args, **kwargs):
    '''
    recommend_func: 推荐模块，取值可以为随机推荐，热门推荐，协同过滤等
    K: 推荐个数
    M: M折验证
    desc: 显示每一轮的指标
    args: 为了将结果导出
    kwarsg: 兼容LFM隐语义模型
    '''
    start0 = time.time()
    recall = precision = cover = popular = 0
    for k in range(M):
        start = time.time()
        train, test = SpliceData(data, M, k, seed = 1234)
        train_dic = list2dict(train)
        test_dic = list2dict(test)
        # 倒排表
        reverse_train_dic = list2dict(train, user_item = False)
        #print(reverse_train_dic)
        # 物品统计表
        item_count = Counter(i for _, i in train)
        if recommend_func == LatenFactorModel:
            recommend = recommend_func(N, *args[1:])
            recommend.fit(train_dic)
        else:
            recommend = recommend_func(N, **kwargs)   # 随机推荐
            recommend.fit(train_dic, item_count, item_user = reverse_train_dic)
        recall_, precision_ = recall_precision(train_dic, test_dic, recommend)
        coverage_ = coverage(train_dic, test_dic, recommend)
        popularity_ = popularity(train_dic, test_dic, recommend, item_count)
        recall += recall_
        precision += precision_
        cover += coverage_
        popular += popularity_
        if desc:
            print("epoch: {}, 召回率: {:.6f}, 精确率: {:.6f}, 覆盖率: {:.6f}, 流行度: {:.6f} =============== 用时{:.2f}s".format(k+1, recall_, 
                                                                                     precision_, coverage_, popularity_, time.time()-start))
    if desc:
        print("\n")
    print("\n[{}] K: {:3d}, 召回率: {:.6f}, 精确率: {:.6f}, 覆盖率: {:.6f}, 流行度: {:.6f} =============== 用时{:.2f}s".format(recommend_func.__name__, N, recall / M, 
                                                                                     precision / M, cover / M, popular / M, time.time()-start0))
    try:
        args[0].append([N, recall / M, precision / M, cover / M, popular / M])
    except Exception as e:
        print(e)
        
class Mythead:
    
    def __init__(self):
        self.res = []
        
    def multi_test(self, data, recommend_func = RandomCF, M = 3, desc = False, K_s = [5, 10, 20, 40, 80, 160],
                  **kwargs):
        """
        data: 数据
        recommend_func: 推荐模块
        M: M折验证
        desc: 默认为False，不显示每一轮的结果
        K_s: 推荐个数列表
        """
        threads = []

        for K in K_s:
            if recommend_func == LatenFactorModel and kwargs:
                #print(kwargs)
                t = threading.Thread(target = my_test, args = (data, recommend_func, K, M, False, self.res, 
                                                           kwargs['user_nums'], kwargs['item_nums'], kwargs['F'],
                                                           kwargs['max_iters'], kwargs['alpha_'],
                                                           kwargs['lambda_'] , kwargs['radio'], kwargs['items_pool']))
            else:
                t = threading.Thread(target = my_test, args = (data, recommend_func, K, M, False, self.res))
            threads.append(t)

        for t in threads:
            t.setDaemon(True)
            t.start()
            
        for t in threads:
            t.join()